package com.pi.shisan.component.impl;

import com.pi.shisan.common.NumberUtil;
import com.pi.shisan.component.AnimationComponent;
import com.pi.shisan.component.util.AnimationThread;
import com.pi.shisan.component.util.ComponentThread;
import com.pi.shisan.component.util.FastIntList;
import com.pi.shisan.component.util.Lunar;
import com.pi.shisan.component.util.SharedSource;
import com.pi.shisan.util.DefaultFont8x8;
import com.pi.shisan.util.spipoint.DataWriter;
import com.pi.shisan.util.spipoint.MergedSpi;
import com.pi.shisan.util.spipoint.MultipleFlushSpi;
import com.pi.shisan.util.spipoint.MultipleFlushSpiAsConsole;
import com.pi.shisan.util.spipoint.MultipleXyToSpiConverter;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.pi.shisan.component.util.SharedMethod.drawPoints;

/**
 * 日期组件
 */
public class LocalDateComponent extends AnimationComponent {

    private List<int[]> weekCache = new ArrayList<>(7);

    private final static Map<String, int[]> CHINESE_TEXT_MAPPING = new HashMap<String, int[]>(){
        {
            put("一",DefaultFont8x8.getPointsAsXy(272678883688448L));
            put("二",DefaultFont8x8.getPointsAsXy(8070450536408678400L));
            put("三",DefaultFont8x8.getPointsAsXy(-576337602840363008L));
            put("四",DefaultFont8x8.getPointsAsXy(-96002195660472320L));
            put("五",DefaultFont8x8.getPointsAsXy(-1134642875548565504L));
            put("六",DefaultFont8x8.getPointsAsXy(2375649149317021696L));
            put("七",DefaultFont8x8.getPointsAsXy(4681562492512501760L));
            put("八",DefaultFont8x8.getPointsAsXy(1175528047856582656L));
            put("九",DefaultFont8x8.getPointsAsXy(4679328319915687936L));
            put("十",DefaultFont8x8.getPointsAsXy(2315123025327947776L));
            put("初",DefaultFont8x8.getPointsAsXy(6839326032630120448L));
            put("廿",DefaultFont8x8.getPointsAsXy(5834501623665131520L));
            put("卅",DefaultFont8x8.getPointsAsXy(6076761436443377664L));
            put("月",DefaultFont8x8.getPointsAsXy(2147483648L));
        }
    };

    /**
     * 上一次绘制过的所有点保存
     */
    private final FastIntList lastAllPoints = new FastIntList();


    /**
     * 组件内容坐标X
     */
    private int fromX;
    /**
     * 组件内容坐标Y
     */
    private int fromY;

    public LocalDateComponent(MultipleXyToSpiConverter spi, DataWriter dataWriter) {
        super(spi,dataWriter);
        init();
    }

    @Override
    protected AnimationThread prepareAnimation() {
        return new LocalDateAnimationThread(this);
    }

    private void init() {
        //MON THU WED THR FIR SAT SUN
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_M));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_O));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_N));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_T));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_U));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_E));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_W));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_E));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_D));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_T));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_H));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_R));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_F));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_I));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_R));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_S));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_A));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_T));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_S));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_U));
//        weekCache.add(DefaultFont8x8.getPointsAsXy(DefaultFont8x8.UPPER_N));

        //一
        weekCache.add(CHINESE_TEXT_MAPPING.get("一"));
        //二
        weekCache.add(CHINESE_TEXT_MAPPING.get("二"));
        //三
        weekCache.add(CHINESE_TEXT_MAPPING.get("三"));
        //四
        weekCache.add(CHINESE_TEXT_MAPPING.get("四"));
        //五
        weekCache.add(CHINESE_TEXT_MAPPING.get("五"));
        //六
        weekCache.add(CHINESE_TEXT_MAPPING.get("六"));
        //日
        weekCache.add(DefaultFont8x8.getPointsAsXy(-537906888310784000L));
    }

    @Override
    public void refresh() {
        if (animationThread != null) {
            ((LocalDateAnimationThread)animationThread).refreshOnly();
        }
    }

    private void doRefresh(int year, int month, int day, int week, Lunar lunar) {
        if (NumberUtil.getNumsOfNum(year) > 2) {
            year = year % 2000;
        }
        int x = fromX;
        int y = fromY;
        lastAllPoints.forEach(spi::delete);
        //修复这个家伙可能带来的内存溢出问题（之前都没做过clear...）
        lastAllPoints.clear();
        int maxY = Short.MIN_VALUE;
        for (int i = 1; i >= 0; i--) {
            int maxX = Integer.MIN_VALUE;
            int[] numPoints = SharedSource.getFromNumCache(NumberUtil.getSimpleNum(year, i));
            int max = drawPoints(numPoints,startX, startY, x, y, maxX,maxY, width, height, spi, lastAllPoints);
            maxX = NumberUtil.toX(max);
            maxY = NumberUtil.toY(max);
            x += maxX + 2;
        }
//        drawPoints(DOT,startX,startY,x,y,0,0,width,height,spi,lastAllPoints);
//        x+= 2;
        for (int i = 1; i >= 0; i--) {
            int maxX = Integer.MIN_VALUE;
            int[] numPoints = SharedSource.getFromNumCache(NumberUtil.getSimpleNum(month, i));
            int max = drawPoints(numPoints,startX, startY, x, y, maxX,maxY, width, height, spi, lastAllPoints);
            maxX = NumberUtil.toX(max);
            maxY = NumberUtil.toY(max);
            x += maxX + 2;
        }
        for (int i = 1; i >= 0; i--) {
            int maxX = Integer.MIN_VALUE;
            int[] numPoints = SharedSource.getFromNumCache(NumberUtil.getSimpleNum(day, i));
            int max = drawPoints(numPoints,startX, startY, x, y, maxX,maxY, width, height, spi, lastAllPoints);
            maxX = NumberUtil.toX(max);
            maxY = NumberUtil.toY(max);
            x += maxX + 2;
        }

//        int index = (week - 1) * 3;
        x+=1;
        int index = week - 1;
        for (int i = index; i < /*index + 3*/ index + 1; i++) {
            int maxX = Short.MIN_VALUE;
            int[] numPoints = weekCache.get(i);
            int max = drawPoints(numPoints,startX, startY, x, y, maxX,maxY, width, height, spi, lastAllPoints);
            maxX = NumberUtil.toX(max);
            maxY = NumberUtil.toY(max);
            x += maxX + 2;
        }
        if (lunar != null) {
            x = fromX;
            y += maxY + 2;
            String cStr = lunar.get_month();
            char[] strs = cStr.toCharArray();
            for (int i = 0; i < strs.length; i++) {
                char c = strs[i];
                int maxX = Integer.MIN_VALUE;
                int[] numPoints = CHINESE_TEXT_MAPPING.get(String.valueOf(c));
                if (numPoints == null) {
                    continue;
                }
                int max = drawPoints(numPoints,startX, startY, x, y, maxX,maxY, width, height, spi, lastAllPoints);
                maxX = NumberUtil.toX(max);
                maxY = NumberUtil.toY(max);
                x += maxX + 2;
            }
            cStr = lunar.get_date();
            strs = cStr.toCharArray();
            for (int i = 0; i < strs.length; i++) {
                char c = strs[i];
                int maxX = Integer.MIN_VALUE;
                int[] numPoints = CHINESE_TEXT_MAPPING.get(String.valueOf(c));
                if (numPoints == null) {
                    continue;
                }
                int max = drawPoints(numPoints,startX, startY, x, y, maxX,maxY, width, height, spi, lastAllPoints);
                maxX = NumberUtil.toX(max);
                maxY = NumberUtil.toY(max);
                x += maxX + 2;
            }
        }
        flushData();
    }

    @Slf4j
    static class LocalDateAnimationThread extends AnimationThread {

        private LocalDateComponent localDateComponent;

        private int year, month, day, week, dayOfYear;
        private Lunar lunar;

        public LocalDateAnimationThread(LocalDateComponent localDateComponent) {
            this.localDateComponent = localDateComponent;
            setName("local-date-animation");
        }

        private void refreshData() {
            LocalDate now = LocalDate.now();
            if (now.getYear() != year || now.getDayOfYear() != dayOfYear) {
                year = now.getYear();
                month = now.getMonthValue();
                day = now.getDayOfMonth();
                week = now.getDayOfWeek().getValue();
                dayOfYear = now.getDayOfYear();
                try {
                    lunar = new Lunar(year,month,day);
                } catch (Exception e) {
                    log.error("创建农历日期对象失败：",e);
                    lunar = null;
                }
            }
        }

        public void refreshOnly() {
            ComponentThread.execute(()->{
                localDateComponent.doRefresh(year, month, day, week, lunar);
            });
        }

        @Override
        protected void doRun() {
            localDateComponent.fromY = localDateComponent.height;
            boolean direct = false; //false: -- true: ++
            refreshData();
            while (!destroy) {
                if (lunar == null && !direct) {
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                    }
                    continue;
                }
                localDateComponent.fromY = direct ? localDateComponent.fromY + 1 : localDateComponent.fromY - 1;
                ComponentThread.execute(()->{
                    localDateComponent.doRefresh(year, month, day, week, lunar);
                });
                if (localDateComponent.fromY == 0 || localDateComponent.fromY == -localDateComponent.height - 1) {
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                    }
                    if (localDateComponent.fromY < -localDateComponent.height) {
                        direct = true;
                    } else if (localDateComponent.fromY <= 0) {
                        direct = false;
                    }
                    refreshData();
                } else {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws Exception{
        MultipleFlushSpi multipleFlushSpi = new MultipleFlushSpiAsConsole(new MergedSpi(4,3));
        LocalDateComponent dateComponent = new LocalDateComponent(multipleFlushSpi,multipleFlushSpi);
        dateComponent.setY(16);
        dateComponent.setH(10);
        dateComponent.setW(20);
        dateComponent.setX(3);
        dateComponent.fromX = -20;
        for (int i = 0; i < 32; i++) {
            dateComponent.start();
            dateComponent.fromX++;
            Thread.sleep(1000);
        }
    }
}
